﻿using System.Threading;
using System.Threading.Tasks;
using System.Collections.Generic;
using System.Linq;
using Zo.Domain.UnitOfWorks;

namespace Zo.Events
{
    /// <summary>
    /// 事件处理器。
    /// </summary>
    public interface IEventHandler
    {
        /// <summary>
        /// 判断指定事件是否能被当前处理器处理。
        /// </summary>
        /// <param name="event">事件。</param>
        /// <returns></returns>
        bool CanHandle(IEvent @event);

        /// <summary>
        /// 处理事件。
        /// </summary>
        /// <param name="event">事件。</param>
        /// <returns>事件处理结果。</returns>
        IEventResult Handle(IEvent @event);

        /// <summary>
        /// 处理事件。
        /// </summary>
        /// <param name="event">事件。</param>
        /// <param name="cancellationToken">取消操作通知。</param>
        /// <returns>事件处理结果。</returns>
        Task<IEventResult> HandleAsync(IEvent @event, CancellationToken cancellationToken = default);
    }

    /// <summary>
    /// 事件处理器。
    /// </summary>
    /// <typeparam name="TEvent">事件类型。</typeparam>
    public interface IEventHandler<in TEvent> : IEventHandler where TEvent : class, IEvent
    {
        /// <summary>
        /// 处理事件。
        /// </summary>
        /// <param name="event">事件。</param>
        /// <param name="cancellationToken">取消操作通知。</param>
        /// <returns>事件处理结果。</returns>
        Task<IEventResult> HandleAsync(TEvent @event, CancellationToken cancellationToken = default);
    }

    /// <summary>
    /// 事件处理器基类。
    /// </summary>
    /// <typeparam name="TEvent">事件类型。</typeparam>
    public abstract class EventHandlerBase<TEvent> : IEventHandler<TEvent> where TEvent : class, IEvent
    {
        /// <summary>
        /// 事件是否可以被当前处理器处理。
        /// </summary>
        /// <param name="event">事件。</param>
        public bool CanHandle(IEvent @event) => @event.GetType().Equals(typeof(TEvent));

        /// <summary>
        /// 处理事件。
        /// </summary>
        /// <param name="event">事件。</param>
        /// <returns>事件处理结果。</returns>
        public IEventResult Handle(IEvent @event)
        {
            return OnHandle((TEvent)@event);
        }

        /// <summary>
        /// 处理事件。
        /// </summary>
        /// <param name="event">事件。</param>
        /// <param name="cancellationToken">取消操作通知。</param>
        /// <returns>事件处理结果。</returns>
        public Task<IEventResult> HandleAsync(TEvent @event, CancellationToken cancellationToken = default)
        {
            return Task.FromResult(OnHandle(@event));
        }

        /// <summary>
        /// 处理事件。
        /// </summary>
        /// <param name="event">事件。</param>
        /// <param name="cancellationToken">取消操作通知。</param>
        /// <returns>事件处理结果。</returns>
        public Task<IEventResult> HandleAsync(IEvent @event, CancellationToken cancellationToken = default)
        {
            return Task.FromResult(OnHandle((TEvent)@event));
        }

        /// <summary>
        /// 处理事件。
        /// </summary>
        /// <param name="event">事件。</param>
        /// <returns>事件处理结果。</returns>
        protected abstract IEventResult OnHandle(TEvent @event);

        protected virtual IEventResult CreateEventResult(IUnitOfWorkResult unitOfWorkResult)
        {
            return CreateEventResult(unitOfWorkResult.Status, null, unitOfWorkResult.ErrorCode, unitOfWorkResult.ErrorMessage);
        }

        protected virtual IEventResult CreateEventResult(bool status, object model = null, string errorCode = "", string errorMessage = "")
        {
            return new EventResult
            {
                Status = status,
                Model = model,
                ErrorCode = errorCode ?? string.Empty,
                ErrorMessage = errorMessage ?? string.Empty
            };
        }
    }

    /// <summary>
    ///
    /// </summary>
    /// <typeparam name="TEvent"></typeparam>
    public abstract class EventHandlerBaseAsnyc<TEvent> : IEventHandler<TEvent> where TEvent : class, IEvent
    {
        /// <summary>
        /// 事件是否可以被当前处理器处理。
        /// </summary>
        /// <param name="event">事件。</param>
        public bool CanHandle(IEvent @event) => @event.GetType().Equals(typeof(TEvent));

        /// <summary>
        /// 处理事件。
        /// </summary>
        /// <param name="event">事件。</param>
        /// <returns>事件处理结果。</returns>
        public IEventResult Handle(IEvent @event)
        {
            throw new System.NotImplementedException();
        }

        /// <summary>
        /// 处理事件。
        /// </summary>
        /// <param name="event">事件。</param>
        /// <param name="cancellationToken">取消操作通知。</param>
        /// <returns>事件处理结果。</returns>
        public Task<IEventResult> HandleAsync(TEvent @event, CancellationToken cancellationToken = default)
        {
            return OnHandle(@event);
        }

        /// <summary>
        /// 处理事件。
        /// </summary>
        /// <param name="event">事件。</param>
        /// <param name="cancellationToken">取消操作通知。</param>
        /// <returns>事件处理结果。</returns>
        public Task<IEventResult> HandleAsync(IEvent @event, CancellationToken cancellationToken = default)
        {
            return OnHandle((TEvent)@event);
        }

        /// <summary>
        /// 处理事件。
        /// </summary>
        /// <param name="event">事件。</param>
        /// <returns>事件处理结果。</returns>
        protected abstract Task<IEventResult> OnHandle(TEvent @event);

        protected virtual IEventResult CreateEventResult(IUnitOfWorkResult unitOfWorkResult)
        {
            return CreateEventResult(unitOfWorkResult.Status, null, unitOfWorkResult.ErrorCode, unitOfWorkResult.ErrorMessage);
        }

        protected virtual IEventResult CreateEventResult(bool status, object model = null, string errorCode = "", string errorMessage = "")
        {
            return new EventResult
            {
                Status = status,
                Model = model,
                ErrorCode = errorCode ?? string.Empty,
                ErrorMessage = errorMessage ?? string.Empty
            };
        }
    }

    public interface IEventResult
    {
        bool Status { get; }

        object Model { get; }

        string ErrorCode { get; }

        string ErrorMessage { get; }

        IEnumerable<IEventResult> Child { get; }
    }

    internal class EventResult : IEventResult
    {
        private bool _state = false;

        private List<IEventResult> _eventResults = new List<IEventResult>();

        public bool Status
        {
            get
            {
                if (Child.Any())
                {
                    return Child.All(item => item.Status);
                }
                else
                {
                    return _state;
                }
            }
            set
            {
                _state = value;
            }
        }

        public object Model { get; set; }

        public string ErrorCode { get; set; }

        public string ErrorMessage { get; set; }

        public IEnumerable<IEventResult> Child => _eventResults.AsReadOnly();

        public void Add(IEventResult EventResult)
        {
            if (EventResult == null)
            {
                return;
            }

            _eventResults.Add(EventResult);
        }
    }
}